﻿# Example AI for University of Colorado Code War 2011
# IronPython implementation by Michael Foord
# http://www.voidspace.org.uk/blog

import clr, sys
clr.AddReference('System.Core')
clr.AddReference('System.Drawing')

import System
import time
from System import (
    Array, 
    Int32,
    Random,
)

# this activates the "FirstOrDefault" method on enumerables
clr.ImportExtensions(System.Linq)

from System.Drawing import Point

from RoboRallyAPI import (
    Card,
    IPlayer,
    MapSquare,
    PlayerSetup,
    PlayerTurn,
    Utilities,
    BoardLocation
)

class MyPlayerBrain(IPlayer):
    """
    The sample IronPython AI. Start with this project but write your own code
    as this is a very simplistic implementation of the AI.
    """
    
    rand = Random()
    
    @property
    def Name(self):
        """The name of the player. A string."""
        return 'Chronotron'

    
    @property
    def Avatar(self):
        """
        The avatar of the player. Must be 32 x 32.
        
        Return a System.Drawing.Image or None
        """
    #image = open('chronotron.png'
        return None
    
    
    def Setup(self, map, you, robotStart):
        """
        Called when your robot must be placed on the board. This is called at
        the start of the game and each time your robot dies.

        
        Takes arguments: map, you, robotStart
        

        map (GameMap): The game map. There will be no units on this map.
        you (Player): Your player object.
        robotStart (Point[] array): The position(s) on the map where you 
        can place your robot. This will be a single point unless another 
        robot is on your archive point.
        
        Returns (PlayerSetup): Where to place your unit (location and direction).
        """
        self.tmp = open("C:\\log.txt", "w")
        self.tmp.write("TEST")
        self.tmp.flush()
        return PlayerSetup(robotStart[0], MapSquare.DIRECTION.NORTH)
        
#    def checkLinesOfFire(self, map, you, allPlayers, moveCards):
#        for eachPlayer in allPlayers:
#            if (eachPlayer)
    
    def Turn(self, map, you, allPlayers, cards):
        try:
			return self.errTurn(map, you, allPlayers, cards)
        except ValueError:
            self.tmp.write(str(sys.exc_info()[2].tb_next.tb_lineno) + "\n")
            self.tmp.flush()
    
    def errTurn(self, map, you, allPlayers, cards):
    #print "TEST"*4000
        """
        Called each time the system needs another turn. If you do not return a 

        valid turn, the game will randomly move one of your units. This call 

        must return in under 1 second. If it has not returned in 1 second the 

        call will be aborted and a random move will be assigned.
        

        Takes arguments: map, you, allPlayers, cards
        

        map (GameMap): The game map. There will be no units on this map.
        you (Player): Your player object. This is created for each call.

        allPlayers (Player[]): All players including you. This is created 
        for each call.
        cards (Card[]): The cards you get to pick from. This does not 

        include locked cards.

        

        Returns (PlayerTurn): Your requested turn.

        """
        #Returns starting time in seconds
        startTime = time.time()
            
        #get robot locations
        robotLocations = ["","","","","","","",""]
	robotLocationsClone = ["","","","","","","",""]
        for i in range(len(allPlayers)):
            robotLocations[i] = allPlayers[i].Robot.Location

            # if hurt bad, consider power down
            powerDown = False
            #if you.Damage > 5 and (self.rand.Next(3) == 0):
            #    powerDown = True
        if you.Damage > 4:#power down if damage gets below a critical threshold
            powerDown = True
        if you.Damage == 4 and (self.rand.Next(2) == 0):
            poiwerDown = True
        

        # get sets until we are done
        best = None
        bestDiff = Int32.MaxValue
        
        fs = you.FlagStates.FirstOrDefault(lambda fs0n: not fs0n.Touched)
        ptFlag = Point(5, 6) if fs is None else fs.Position #flag point
        

        #robotMove = [Card.BACKWARD_ONE, Card.FORWARD_ONE, Card.FORWARD_TWO, Card.FORWARD_THREE, Card.ROTATE_LEFT, Card.ROTATE_RIGHT, Card.ROTATE_UTURN]
        while (True):
        #for turnOn in range(MAX_COMBINATIONS):
        #set diff
            diff = 0
            # pick 5 (or fewer if locked) random cards
            moveCards = Array.CreateInstance(Card, 5)
            moveCardsOther = []
            for i in range(len(moveCards)):
            	moveCardsOther.append(Array.CreateInstance(Card, 5))
            Cards = Array.CreateInstance(Card, 5)
            cardUsed = Array.CreateInstance(bool, cards.Length)
            

            for ind in range(5 - you.NumLockedCards):
                while True:
                    index = self.rand.Next(cards.Length)
                    if cardUsed[index]:
                        continue
                    moveCards[ind] = cards[index]
                    cardUsed[index] = True
                    break
           
            # add in the locked cards
            for ind in range(5 - you.NumLockedCards, 5):
                moveCards[ind] = you.Cards[ind]
            
            #for i in range(len(moveCards)):
            #    robotLocationsClone[i] = allPlayers[i].Robot.Location
            #for j in range(len(moveCards)):
            #    robotLocationsClone[0] = Utilities.CardPath(map, robotLocationsClone[0], moveCards[0:j])
                #move the other robots
                
            #    for i in range(1, len(robotLocationsClone)):    
            #        moveCardsOther[i][j] = Card(self.rand.Next(7),999 - i)
            #        robotLocationsClone[i] = Utilities.CardPath(map, robotLocationsClone[i], moveCards[0:j])
            #        #calculate damage
            #    diff += 3*CalcLaserDamage(map, robotLocationsClone[0])

            mp = Utilities.CardDestination(map, you.Robot.Location, moveCards)
            if mp.Dead:
                continue
            
            # if better than before, use it
            diff = diff + abs(ptFlag.X - mp.Location.MapPosition.X) + abs(ptFlag.Y - mp.Location.MapPosition.Y)
            #if diff <= okDiff:
            #return PlayerTurn(moveCards, powerDown)
        
            if diff < bestDiff:
                bestDiff = diff
                best = moveCards
            

            #Return endtime in seconds
            endTime = time.time()
            totalTime = endTime - startTime

            if totalTime > 0.98:
                return PlayerTurn(best, powerDown)

        return PlayerTurn(best, powerDown)
